const { toASCII } = require('punycode');
const { callbackify } = require('util');

/* 
    前提：修改过结构了
    第一步：这里需要按逻辑把代码分成两部分
        -- 第一部分：计算详单所需数据
        -- 第二部分：渲染数据为 html 格式
        -- 第一阶段会创建一个中转数据结构，再把它传递给第二阶段
    第二步：对第二部分的代码进行提炼函数
        1. 把 statement() 的全部代码抽取到一个新的函数中
        2. 新建一个中转的数据结构变量 statementData
            -- 检查 renderPlainText() 中的其它参数，我们希望它们都能挪到这个中转数据结构里
            -- 声明 statementData.customer = invoice.customer
            -- 把 renderPlainText() 中的 invoice.customer 换成 data.customer
            -- 把 renderPlainText() 中的 invoice.performance 换成 data.performance
            -- 移除 renderPlainText() 的 invoice 参数
            -- 用 play.json 中的数据副本填充 statementData.performance（目的是不修改传给函数的参数）
        3. 给 enrichPerformance() 函数增加数据
            -- result.play = playFor(result); 并复制 playFor() 到 enrichPerformance()
            -- 替换 renderPlainText()中的 playFor()所有的引用点，然后删除 renderPlainText()中的playFor()
            -- 搬移 amountFor()
            -- 搬移 volumeCreditsFor()
            -- 搬移 totalAmount()
            -- 搬移 totalVolumeCredits()
            -- 优化代码：用管道取代循环(本地代码不支持)
        4. 把代码分离到两个文件
*/
function statement(invoice, plays){
    return renderPlainText(createStatementData(invoice, plays));
}
function createStatementData(invoice, plays){
    const statementData= {};
    statementData.customer = invoice.customer;
    // map() 方法通过对每个数组元素执行函数来创建新数组。
    statementData.performance = invoice.performance.map(enrichPerformance);
    statementData.totalAmount = totalAmount(statementData);
    statementData.totalVolumeCredits = totalVolumeCredits(statementData);
    return statementData;

    /* 
        返回一个浅副本
        Object.assign 方法只会拷贝源对象自身的并且可枚举的属性到目标对象身上
    */
    function enrichPerformance(aPerformance){
        // Object.assign(target, source)
        const result = Object.assign({},aPerformance);
        result.play = playFor(result);
        result.amount = amountFor(result);
        result.volumeCredits = volumeCreditsFor(result);
        return result;
    }
    
    function playFor(aPerformance){
        return plays[aPerformance.playID];
    } 
    
    function amountFor(aPerformance){
        let result = 0;
        switch (aPerformance.play.type) {
            case "tragedy":
                result = 40000;
                if (aPerformance.audience > 30) {
                    result += 1000 * (aPerformance.audience - 30);
                }
                break;
            case "comedy":
                result = 3000;
                if (aPerformance.audience > 20) {
                    result += 1000 + 500 * (aPerformance.audience - 20);
                }
                break;
            default:
                throw new Error("unknown type:" +aPerformance.play.type);
        }
        return result;
    }
    
    function volumeCreditsFor(aPerformance){
        let result = 0;
        result += Math.max(aPerformance.audience - 30, 0);
        if ("comedy" ===  aPerformance.play.type) {
            result += Math.floor(aPerformance.audience/5);
        }
        return result;
    }

    function totalAmount(data){
        let result = 0;
        for (let perf of data.performance) {
            result += perf.amount;
        };
        return result;

        // 用管道取代循环
        // return data.performance.reduce((total,p)=>{total+p.amount,0});
    }
    function totalVolumeCredits(data){
        let result = 0;
        for (let perf of data.performance) {
            result += perf.volumeCredits;
        }
        return result;
        // return data.performance.reduce((total,p)=>{total+p.volumeCredits,0});
    }
}

function renderPlainText(data) {
    let result = "Statement for " + data.customer + "\n";
    for (let perf of data.performance) {
        result += "-- " +  perf.play.name + ": " + usd(perf.amount) + " (" + perf.audience + " seats)" + "\n";
    };

    result += "Amount owed id " + usd(data.totalAmount) + "\n";
    result += "You earned " + data.totalVolumeCredits + " credits";
    console.log(result);
    return result;

    function usd(aNumber){
        return new Intl.NumberFormat("en-US", {
            style: "currency", currency: "USD",
            minimumFractionDigits: 2
        }).format(aNumber/100);
    }
}

/****************************************** */
function readJson(fileName, callback) {
    var fs = require('fs');
    fs.readFile(fileName, 'utf-8', (err, data) => {
        if (err) {
            console.error(err);
        } else {
            callback(JSON.parse(data));
        }
    });
}

var invoice;
var play;
readJson("invoices.json", (myData) => {
    invoice = myData;
});
readJson("play.json", (myData) => {
    play = myData;
});
var timer = setInterval(() => {
    if (invoice) {
        clearInterval(timer);
        // console.log({ invoice });
        // console.log({ play });
        statement(invoice, play);
    }
}, 500);


